package org.gwt.grin.client;

import org.gwt.grin.client.commands.Command;
import org.gwt.grin.client.features.Assembly;

import com.google.gwt.core.client.GWT;

/**
 * This class is a super type that {@code EntryPoint} implementations can
 * subclass to interact with a show.
 * 
 * @author Bill Foote (http://jovial.com)
 * @author ggeorg
 */
public class Director {

	private Show show;

	/**
	 * Get the show we're managing.
	 * 
	 * @return the show
	 */
	public Show getShow() {
		return show;
	}

	/**
	 * Called from the {@link ShowBuilder#buildShow(Director)} method.
	 */
	void setShow(Show show) {
		this.show = show;
	}

	/**
	 * Get the named public feature from the show we're managing. If not found
	 * and if we're in debug mode, trigger an assertion failure.
	 * <p>
	 * This method does search through all the show's features using a hashtable
	 * lookup, so it shouldn't be called frequently; it's best used during
	 * initialization.
	 * 
	 * @param name
	 *            the feature's name
	 * @return the named feature or {@code null} if not found
	 */
	public Feature getFeature(String name) {
		Feature f = getShow().getFeature(name);
		assert f != null : "Feature \"" + name + "\" not found";
		return f;
	}

	/**
	 * Get the named public command (or command list) from the show we're
	 * managing. If not found and if we're in debug mode, trigger an assertion
	 * failure. This method does a search through the show's named commands
	 * using a hashtable lookup, so it shouldn't be called too frequently; it's
	 * best used during initialization.
	 * <p>
	 * The returned Command object can be used in a call to runCommand(Command)
	 * on the show from where it came. If you send a named command to a
	 * different show, the results are undefined.
	 * 
	 * @param name
	 *            the command's name
	 * @return the named command or {@code null} if not found
	 */
	public Command getNamedCommand(String name) {
		Command c = getShow().getNamedCommand(name);
		if (GWT.isClient() && c == null) {
			GWT.log("Named command \"" + name + "\" not found.");
		}
		return c;
	}

	/**
	 * Look up the named part in the given assembly. If not found and if we're
	 * in debug mode, trigger an assertion failure. This method does a search
	 * through the assembly's parts, so it shouldn't be called frequently; it's
	 * best used during initialization.
	 * 
	 * @param assembly
	 *            the given {@link Assembly}
	 * @param partName
	 *            the part's name
	 * @return the named assembly part or {@code null} if not found
	 */
	public Feature getPart(Assembly assembly, String partName) {
		Feature[] parts = assembly.getParts();
		String[] partNames = assembly.getPartNames();
		for (int i = 0; i < parts.length; i++) {
			if (partName.equals(partNames[i])) {
				return parts[i];
			}
		}
		if (GWT.isClient()) {
			GWT.log("Part \"" + partName + "\" not found in " + assembly + ".");
		}
		return null;
	}

	/**
	 * Look up the given named public segment in the show we're managing. If not
	 * found and if we're in debug mode, trigger an assertion failure. This
	 * method does a search through the show's features using a hashtable
	 * lookup, so it shouldn't be called frequently; it's best used during
	 * initialization.
	 * 
	 * @param name
	 * @return
	 */
	public Segment getSegment(String name) {
		Segment s = getShow().getSegment(name);
		assert s != null : "Segment \"" + name + "\" not found";
		return s;
	}

	/**
	 * Notify the director that the model is moving to the next frame.
	 * Subclasses that override this method must call {@link
	 * super#notifyNextFrame()} at least once. The implementation of this method
	 * in {@code Director} causes the show to execute all pending commands,
	 * which can result in model state changes, such as selecting new segments,
	 * changing the selected part in an assembly, etc. Usually, you'll probably
	 * want to call {@link super#notifyNextFrame()} first thing, but it may
	 * beuseful in some circumstances to do some computation before, e.g.
	 * something that might result in posting a command to the show.
	 * <p>
	 * This method is called after the scene graph's model has moved to the
	 * upcomming frame's state. Applications that override this method may wish
	 * to update user-programmable node values in the body of this method. This
	 * method and the execute() body of a command are the only safe times for
	 * user code to update show nodes.
	 * <p>
	 * If you want to run some Java code to update the scene graph for every
	 * frame when the show is on certain states, it might be easier to make a
	 * timer that goes off every frame, invoking a java_command.
	 */
	public void notifyNextFrame() {
		show.runPendingCommands();
	}

	/**
	 * Notify the director that a new segment has been activated.
	 * <p>
	 * The default implementation of this method does nothing, so there is no
	 * need to call {@link super#notifySegmentActivated(Segment, Segment)}.
	 * 
	 * @param newSegment
	 *            the new segment that was activated
	 * @param oldSegment
	 *            the old segment that was previously active
	 */
	public void notifySegmentActivated(Segment newSegment, Segment oldSegment) {
	}

	/**
	 * Notifies the director that the underlying show has been destroyed. If the
	 * director has acquired any resources, it should release them here.
	 */
	public void notifyDestroyed() {
	}

	public void notifyAssemblyPartSelected(Assembly assembly, Feature feature,
			Feature currentPart, boolean activated) {
		// TODO Auto-generated method stub

	}

}
